package com.jh.fcsm.common.aspect;

import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.jh.fcsm.common.annotation.EncryptField;
import com.jh.fcsm.constant.TokenConstants;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.List;

//@Aspect
//@Component
public class EncryptAop {
    private static final Logger logger = LoggerFactory.getLogger(EncryptAop.class);
    /**
     * 定义加密切入点
     */
//    @Pointcut(value = "execution(* com.jh.*.controller.*.*Controller.*(..))")
//    @Pointcut(value = "execution(* com.jh.*.dao.*.*Mapper.*(..))")
//    public void point() {
//    }

    /**
     * 命中加密切入点的环绕通知
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
//    @Around("point()")
    public static Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //获取命中目标方法的入参数
        Object[] args = proceedingJoinPoint.getArgs();
        if (args.length > 0) {
            for (Object arg : args) {
                //按参数的类型进行判断，如果业务中还有其他的类型，可酌情增加
                if (arg != null) {
                    if (arg instanceof List) {
                        for (Object tmp : ((List) arg)) {
                            //加密处理
                            deepProcess(tmp);
                        }
                    } else {
                        deepProcess(arg);
                    }
                }
            }
        }
        //对敏感数据加密后执行目标方法
        return proceedingJoinPoint.proceed();
    }

    public static void deepProcess(Object obj) throws Exception {
        if (obj != null) {
            //获取对象的所有字段属性并遍历
            Field[] declaredFields = obj.getClass().getDeclaredFields();
            for (Field declaredField : declaredFields) {
                //判断字段属性上是否标记了@EncryptField注解
                if (declaredField.isAnnotationPresent(EncryptField.class)) {
                    //如果判断结果为真，则取出字段属性值，进行加密、重新赋值
                    declaredField.setAccessible(true);
                    Object valObj = declaredField.get(obj);
                    if (valObj != null) {
                        String value = valObj.toString();
                        //开始敏感字段属性值加密
                        String decrypt = encrypt(value);
                        //把加密后的字段属性值重新赋值
                        declaredField.set(obj, decrypt);
                    }
                }
            }
        }
    }
    private static String encrypt(String value) throws Exception {
        SymmetricCrypto sm4 = SmUtil.sm4(TokenConstants.SM4_DATA_SECRET.getBytes());
        return sm4.encryptBase64(value, StandardCharsets.UTF_8);//库加密结果
    }

}
